
import { checkPermi, checkRole } from "@/utils/permission";
const common = {
  //树状结构排序函数
  sortChildren(node, sortField, sortOrder = 'asc') {
    if (Array.isArray(node.children)) {
      node.children.sort((a, b) => {
        if (sortOrder === 'asc') {
          // 假设sortField是字符串  
          return a[sortField].localeCompare(b[sortField]);
          // 如果sortField是数值  
          // return a[sortField] - b[sortField];  
        } else if (sortOrder === 'desc') {
          // 字符串  
          return b[sortField].localeCompare(a[sortField]);
          // 数值  
          // return b[sortField] - a[sortField];  
        }
      });

      // 递归地对每个子节点的子节点进行排序  
      node.children.forEach(child => this.sortChildren(child, sortField, sortOrder));
    }
  },

  //生成树状结构
  buildTree(items, excludeIds = [], parentIdField = 'parentId', idField = 'id', childrenField = 'children', sortField = 'orderNum', sortOrder = 'desc') {
    // 创建一个映射来快速查找父项  
    const parentIdMap = {};
    items.forEach(item => {
      parentIdMap[item[idField]] = { ...item }; // 不初始化children字段  
    });



    // 构建树形结构  
    const tree = [];
    items.forEach(item => {
      const parentId = item[parentIdField];
      const itemId = item[idField];


      // 如果parentId是null或者空字符串，那么它是一个根节点  
      if (parentId == null || parentId === '' || parentId === '0') {
        tree.push(parentIdMap[itemId]);
      } else {
        // 否则，尝试将其添加到其父项的children数组中  
        if (!parentIdMap[parentId]) {
          // 如果找不到父项，可能是因为数据不完整，可以选择忽略或抛出错误  
          console.warn(`Parent ID ${parentId} not found for item ${itemId}`);
        } else {
          // 检查父节点是否有children字段，如果没有且当前是第一个子节点，则不添加children字段  
          if (!parentIdMap[parentId][childrenField]) {
            if (Object.keys(parentIdMap[parentId]).indexOf(childrenField) === -1) {
              parentIdMap[parentId][childrenField] = [];
            }
            parentIdMap[parentId][childrenField] = [parentIdMap[itemId]]; // 添加children数组并放入子节点  
          } else {
            // 父节点已有children数组，直接添加子节点  
            parentIdMap[parentId][childrenField].push(parentIdMap[itemId]);
          }
        }
      }
    });

    // 返回生成的树，并清理作为属性添加的子节点（如果需要），同时过滤掉不想展示的节点  
    var res = tree.map(rootNode => {
      // 递归清理子节点的直接属性添加（如果需要），过滤并排序节点  
      function cleanupAndSort(node) {
        // 如果节点ID在excludeIds中，则跳过该节点（不处理也不返回）  
        if (excludeIds.includes(node[idField])) {
          return null;
        }

        if (node[childrenField]) {
          // 递归处理子节点，并过滤掉不想展示的节点  
          node[childrenField] = node[childrenField]
            .map(cleanupAndSort) // 递归清理和过滤  
            .filter(child => child !== null) // 过滤掉null值  
        } else {
          // 如果没有children数组但有直接以ID为属性的子节点，则转换为children数组（如果需要）  
          Object.keys(node).forEach(key => {
            if (parentIdMap[key] && parentIdMap[key].parentId === node[idField] && !excludeIds.includes(key)) {
              if (!node[childrenField]) {
                node[childrenField] = [];
              }
              node[childrenField].push(parentIdMap[key]);
              delete node[key]; // 删除直接以ID为属性的子节点  
            }
          });
        }
        // 在此处也可以根据sortField对node进行排序，但通常根节点不需要（取决于具体需求）  
        return node;
      }

      // 清理并返回根节点，同时过滤掉可能为null的子节点  
      return cleanupAndSort(rootNode);
    }).filter(node => node !== null);// 过滤掉可能为null的根节点  

    // 对每个根节点的子节点进行排序  
    res.forEach(node => this.sortChildren(node, sortField, sortOrder));
    return res;
  },


  //select 选择数据格式化
  selectListFormat(list, def_obj = { userId: 0 }, set_key = 'userId', set_type = 'type', split = ':') {
    var arr = [];
    list.forEach(value => {
      var def = JSON.parse(JSON.stringify(def_obj));

      if (value.includes(split)) {
        //如果有分隔符
        var value_arr = value.split(split);
        def[set_type] = value_arr[0];//先把类型填上
        if (typeof set_key !== 'string') {
          //不是字符串类型说明要根据类型分别设置字段
          def[set_key[def[set_type]]] = value_arr[1];
        } else {
          def[set_key] = value_arr[1];
        }
      } else {
        def[set_key] = value;
      }
      arr.push(def);
    });
    return arr;
  },

  //select 选择数据反格式化
  selectListUnFormat(list, key = 'userId', type = 'type', split = ':') {
    var arr = [];
    list.forEach(item => {
      var value = '';
      if (item[type]) {
        if (typeof key !== 'string') {
          //不是字符串类型说明要根据类型分别设置字段
          value = `${item[type]}${split}${item[key[item[type]]]}`;
        } else {
          value = `${item[type]}${split}${item[key]}`;
        }
      } else {
        value = item[key];
      }
      arr.push(value);
    });
    return arr;
  },



  //金额格式化
  formatAmount(amount) {
    // 设定单位数组，只包含“元”、“万”和“亿”
    const units = ['元', '万', '亿'];

    // 阈值数组，用于从“元”到“万”再到“亿”的转换
    const thresholds = [10000, 100000000];

    // 遍历单位数组，找到合适的单位
    let unitIndex = 0;
    for (let i = 0; i < thresholds.length && amount >= thresholds[i]; i++) {
      amount /= thresholds[i];
      unitIndex = i + 1;
    }

    // 格式化金额，保留两位小数
    amount = amount.toFixed(2);

    // 返回格式化后的金额和单位
    return `${amount}${units[unitIndex]}`;
  },
  //修改对象值 多维嵌套对象
  handleNestedObject(obj, path, value) {
    const pathArray = path.split('.');
    let currentLevel = obj;
    let lastIndex = pathArray.length - 1;

    // 遍历路径数组中的每一个属性名  
    for (let i = 0; i < lastIndex; i++) {
      const key = pathArray[i];

      // 如果当前层级的属性不存在，并且是在设置值的情况下，则创建它（假设为对象）  
      if (!(key in currentLevel) && arguments.length > 2) {
        currentLevel[key] = {};
      }

      // 确保当前层级的属性是一个对象，以便我们可以继续深入  
      if (typeof currentLevel[key] !== 'object' || currentLevel[key] === null) {
        if (arguments.length > 2) {
          throw new Error(`Cannot set nested object value: ${pathArray[i]} is not an object or is null.`);
        } else {
          return undefined; // 获取值时，如果路径中的某个属性不存在，则返回undefined  
        }
      }

      // 移动到下一级  
      currentLevel = currentLevel[key];
    }

    // 获取或设置最后一级的值  
    const lastKey = pathArray[lastIndex];
    if (arguments.length > 2) {
      // 设置值  
      currentLevel[lastKey] = value;
    } else {
      // 获取值  
      return currentLevel[lastKey];
    }
  },
  //时间选择校验返回禁用日期
  handleDateStartChange(that, startField, endField, disabledDateFidel, dateFormat = '{y}-{m}-{d}') {
    var date1 = this.handleNestedObject(that, startField);
    var date2 = this.handleNestedObject(that, endField);
    var val = date1;
    var compare_val = date2;

    // 更新date2的可选范围  
    var disabledDate = (time) => {
      if (!val) return false;
      // return time.getTime() > new Date(val).getTime(); // 禁止选择大于或等于date2的日期  
      var timeText = that.parseTime(time.getTime(), dateFormat);
      var valText = that.parseTime(new Date(val).getTime(), dateFormat);
      return timeText < valText;
    };
    if (disabledDateFidel) {
      this.handleNestedObject(that, disabledDateFidel, disabledDate);
    }

    // 检查date1是否大于date2，如果是则重置date1  
    var compareValText = that.parseTime(new Date(compare_val).getTime(), dateFormat);
    var valText = that.parseTime(new Date(val).getTime(), dateFormat);
    if (compare_val && valText > compareValText) {
      that.$message.error('开始日期不能大于结束日期');
      this.handleNestedObject(that, startField, null);
    }
  },
  //时间选择校验返回禁用日期
  handleDateEndChange(that, startField, endField, disabledDateFidel, dateFormat = '{y}-{m}-{d}') {
    var date1 = this.handleNestedObject(that, startField);
    var date2 = this.handleNestedObject(that, endField);
    var val = date2;
    var compare_val = date1;

    // 更新date1的可选范围  
    var disabledDate = (time) => {
      if (!val) return false;
      // return time.getTime() > new Date(val).getTime(); // 禁止选择大于或等于date2的日期  
      var timeText = that.parseTime(time.getTime(), dateFormat);
      var valText = that.parseTime(new Date(val).getTime(), dateFormat);
      return timeText > valText;
    };
    if (disabledDateFidel) {
      this.handleNestedObject(that, disabledDateFidel, disabledDate);
    }

    // 检查date2是否小于date1，如果是则重置date2  
    var compareValText = that.parseTime(new Date(compare_val).getTime(), dateFormat);
    var valText = that.parseTime(new Date(val).getTime(), dateFormat);
    if (compare_val && valText < compareValText) {
      that.$message.error('结束日期不能小于开始日期');
      this.handleNestedObject(that, endField, null);
    }
  },
  //数字转大写
  convertToChineseNumber(num) {
    var chineseNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九'];
    var chineseDigits = ['', '十', '百', '千'];
    var chineseUnits = ['', '万', '亿'];
    var chineseNum = '';

    function convertPart(numPart) {
      var str = numPart.toString();
      var len = str.length;
      var result = [];

      if (len == 2 && numPart < 20) { // 特殊处理10到19的两位数
        return chineseNums[numPart]; // 直接返回特殊形式
      }

      for (var i = 0; i < len; i++) {
        var digit = parseInt(str.charAt(i), 10);
        if (digit !== 0 || (result.length > 0 && i < len - 1)) {
          result.push(chineseNums[digit] + (len - i - 1 >= 0 ? chineseDigits[len - i - 1] : ''));
        }
      }

      return result.join('').replace(/零+/g, '零');
    }

    if (num === 0) {
      return '零';
    }

    var parts = num.toString().split('.');
    var integerPart = parts[0];
    var decimalPart = parts[1] || '';

    var unitIndex = 0;
    while (integerPart.length > 4) {
      var part = integerPart.slice(-4);
      chineseNum = convertPart(part) + (unitIndex > 0 ? chineseUnits[unitIndex] : '') + (chineseNum ? chineseNum : ''); // 确保首次不添加多余的单位
      integerPart = integerPart.slice(0, -4);
      unitIndex++;
    }

    if (integerPart) {
      chineseNum = convertPart(integerPart) + (unitIndex > 0 ? chineseUnits[unitIndex] : '') + (chineseNum ? chineseNum : '');
    }

    if (decimalPart) {
      chineseNum += '点' + decimalPart.split('').map(d => chineseNums[parseInt(d)]).join('');
    }

    // 特殊处理开头的零和不规范的零
    chineseNum = chineseNum.replace(/^零+(?!\.|$)/, ''); // 移除整数部分开头不必要的零
    if (chineseNum.endsWith('零')) {
      chineseNum = chineseNum.replace(/零+$/, ''); // 移除数字部分结尾的零
    }

    return chineseNum;
  },
  //获取日期范围
  getDateRange(startDate, endDate, includeEnds, returnTimestamps = false, dateFormat = 'yyyy-MM-dd') {
    // 解析开始和结束日期为时间戳  
    let startDateTimestamp = startDate;
    let endDateTimestamp = endDate;

    function parseDateFromString(dateStr, dateFormat = 'yyyy-MM-dd') {
      // 这里应该使用日期解析库（如 moment.js）来处理各种日期格式  
      // 示例中简化处理，仅支持 'yyyy-MM-dd' 格式  
      const date = new Date(dateStr);
      return isNaN(date.getTime()) ? null : date.getTime();
    }

    // 如果日期是字符串，则转换为时间戳  
    if (typeof startDate === 'string') {
      startDateTimestamp = parseDateFromString(startDate, dateFormat);
    }
    if (typeof endDate === 'string') {
      endDateTimestamp = parseDateFromString(endDate, dateFormat);
    }

    if (!startDateTimestamp || !endDateTimestamp) {
      // throw new Error('Invalid date inputs');
      return [];
    }

    // 确保开始日期小于或等于结束日期  
    if (startDateTimestamp > endDateTimestamp) {
      [startDateTimestamp, endDateTimestamp] = [endDateTimestamp, startDateTimestamp];
    }

    // 初始化日期数组  
    const dateRange = [];

    // 循环添加日期  
    let currentTimestamp = startDateTimestamp;
    let shouldContinue = true;

    while (shouldContinue) {
      // 根据 returnTimestamps 参数决定返回字符串还是时间戳  
      if (returnTimestamps) {
        dateRange.push(currentTimestamp);
      } else {
        // 使用 parseTime 来格式化日期（这里假设 parseTime 实际上是格式化时间戳为字符串的函数）  
        // 注意：这里可能需要一个实际的格式化函数，因为 parseTime 听起来像是解析函数  
        const formattedDate = new Date(currentTimestamp).toISOString().slice(0, 10); // 示例：使用原生 JavaScript 格式化  
        // 或者你可以使用 moment.js 等库来更灵活地格式化日期  
        dateRange.push(formattedDate);
      }

      // 递增日期  
      currentTimestamp += 24 * 60 * 60 * 1000; // 一天的时间戳增量  

      // 检查是否超出结束日期  
      shouldContinue = includeEnds ? currentTimestamp <= endDateTimestamp : currentTimestamp < endDateTimestamp;
    }

    return dateRange;
  },
  //对象赋值只赋值有的属性返回一个新对象
  deepMergeExistingProperties(source, target) {
    // 创建一个目标对象的浅拷贝作为结果对象  
    const result = { ...source };

    for (let key in target) {
      // if (result.hasOwnProperty(key)) {
      // 如果属性是对象，则递归调用  
      if (typeof target[key] === 'object' && target[key] !== null &&
        typeof result[key] === 'object' && result[key] !== null) {
        // 递归深拷贝嵌套对象  
        result[key] = deepMergeExistingProperties(target[key], result[key]);
      } else {
        // 直接赋值非对象属性  
        result[key] = target[key];
      }
      // }
    }

    // 返回深拷贝后的结果对象  
    return result;
  },
  //获取某个区间
  getDateRangeByType(type, start = 0, end = 0) {
    // 调整日期到最近的周一
    function adjustToMonday(date) {
      const dayOfWeek = date.getDay();
      const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // 如果今天是周日，差值为-6，否则差值为周一与今天之间的天数
      return new Date(date.getTime() + diff * 24 * 60 * 60 * 1000); // 返回调整后的周一日期
    }

    // 辅助函数：调整日期到周期的结束点（例如，周日）
    function adjustToEndOfWeek(date) {
      const dayOfWeek = date.getDay();
      const diff = dayOfWeek === 0 ? 0 : 7 - dayOfWeek; // 如果今天是周日，差值为0，否则差值为周日至今天之间的天数
      return new Date(date.getTime() + diff * 24 * 60 * 60 * 1000); // 返回调整后的周日日期
    }

    const now = new Date();

    // 定义不同类型的时间周期处理函数
    const handlers = {
      year: function (years) {
        return new Date(now.getFullYear() + years, 0, 1); // 设置日期到特定年份的1月1日
      },
      month: function (months) {
        return new Date(now.getFullYear(), now.getMonth() + months, 1); // 设置日期到特定月份的1号
      },
      week: function (weeks) {
        const adjustedNow = adjustToMonday(now); // 首先将当前日期调整到最近的周一
        return new Date(adjustedNow.getTime() + weeks * 7 * 24 * 60 * 60 * 1000); // 根据周数偏移量返回新日期
      },
      day: function (days) {
        return new Date(now.getTime() + days * 24 * 60 * 60 * 1000); // 根据天数偏移量返回新日期
      }
    };

    if (!handlers[type]) {
      throw new Error(`无效的类型：${type}`);
    }

    // 计算开始日期
    let startDate = handlers[type](start);
    startDate.setHours(0, 0, 0, 0); // 重置开始日期的时间部分到午夜


    // 根据类型调整开始日期到周期的起始点
    switch (type) {
      case 'year':
        startDate.setMonth(0, 1); // 确保开始日期为1月1日
        break;
      case 'month':
        startDate.setDate(1); // 确保开始日期为每月的1号
        break;
      case 'week':
        startDate = adjustToMonday(startDate); // 确保开始日期为周一
        break;
      case 'day':
        break; // 对于天数，不需要额外的调整
    }

    // 计算结束日期
    let endDate = handlers[type](start + end);
    endDate.setHours(23, 59, 59, 999); // 重置结束日期的时间部分到最后时刻

    // 根据类型调整结束日期到周期的结束点
    switch (type) {
      case 'year':
        endDate.setMonth(11, 31); // 确保结束日期为12月31日
        break;
      case 'month':
        endDate.setDate(new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0).getDate()); // 确保结束日期为该月的最后一天
        break;
      case 'week':
        endDate = adjustToEndOfWeek(endDate); // 确保结束日期为周日
        break;
      case 'day':
        break; // 对于天数，不需要额外的调整
    }

    return [startDate, endDate];
  },
  filterByWhere(obj, where) {
    for (const key in where) {
      if (where.hasOwnProperty(key)) {
        const whereValue = where[key];
        const value = obj[key];

        // 检查对象 obj 是否有与 where 相同的属性  
        if (!(key in obj)) {
          continue;
        }

        // 如果whereValue是一个函数，则使用该函数进行比较  
        if (typeof whereValue === 'function') {
          if (!value(value)) {
            return false;
          }
        } else {
          // 如果whereValue是字符串且whereValue是数组，检查whereValue是否在数组中  
          if (typeof value === 'string' && Array.isArray(whereValue)) {
            if (!whereValue.includes(value)) {
              return false;
            }
          } else {
            // 否则，直接进行等于比较  
            if (value !== whereValue) {
              return false;
            }
          }
        }
      }
    }
    return true;
  },
  dictFilter(array, where) {
    return array.filter(item => {
      const raw = item.raw;
      return this.filterByWhere(raw, where)
    });
  },
  isUrl(str) {
    // 简化版的URL匹配正则表达式  
    // 注意：这不会捕获所有可能的URL格式，但会捕获很多常见的格式  
    var urlRegex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;

    return urlRegex.test(str);
  },
  objectToQueryString(obj, prefix = '') {
    var str = [];
    for (var p in obj) {
      if (obj.hasOwnProperty(p)) {
        var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
        str.push(typeof v == "object" ?
          objectToQueryString(v, k) :
          encodeURIComponent(k) + "=" + encodeURIComponent(v));
      }
    }
    return str.join("&");
  },
  //获取按钮宽度operation
  getOperationWidth(arr, num = 0) {
    var defWidth = 50;
    var width = 50;
    for (let index = 0; index < arr.length; index++) {
      const element = arr[index];
      var permi = element.permi;
      var setWidth = element.width;
      var auth = false;
      if (permi == '' || !permi) {
        auth = true;
      } else if (checkPermi([permi])) {
        auth = true;
      }

      if (auth) {
        width += setWidth ?? defWidth;
      }

    }
    console.log('计算宽度', width);
    return width;
  }
};
export default common;
















// 基础样例
// data.approvalList = selectListFormat(data.approvalList);
// data.approvalList = selectListUnFormat(data.approvalList);
// 进阶样例 列如分组拆分和解析
// data.recipientList = selectListFormat(this.form.recipientList, {"type": "0"},{'1':'userId','2':'deptId'});
// data.recipientList = selectListUnFormat(data.recipientList,{'1':'userId','2':'deptId'});